﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BCCommon;
using System.Text;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using BCDto.Website.User;
using BCTMSRESTful.Configs;
using BCService.Utils;
using BCService.Website.User;
using Microsoft.AspNetCore.Authorization;
using BCService.SmsService;
using BCDto.Common.Logon;
using BCCommon.Enums;
using System.Security.Claims;
using BCService.Website.UserAuth;
using BCDto.Website.UserAuth;
using BCService.WeChatComponent.WeChatLoginService;


namespace BCTMSRESTful.Controllers.Anonymous
{
    /// <summary>
    /// 用户信息
    /// </summary>
    [Route("api/v1/[controller]")]
    public class UserController : WebsiteBaseController
    {
        private readonly TimeSpan expiration = TimeSpan.FromDays(7);
        private readonly IUserService userService;
        private readonly IUserAuthService userAuthService;
        private readonly IWeChatLoginService weChatLoginService;
        private readonly IAliyunSmsService aliyunSmsService;

        public UserController(IUserService userService, IUserAuthService userAuthService, IWeChatLoginService weChatLoginService, IAliyunSmsService aliyunSmsService)
        {
            this.userService = userService;
            this.userAuthService = userAuthService;
            this.weChatLoginService = weChatLoginService;
            this.aliyunSmsService = aliyunSmsService;
        }

        #region 用户注册
        /// <summary>
        /// 用户注册
        /// </summary>
        /// <param name="dto">用户注册请求模型</param>
        /// <response code="200">Token</response>
        /// <returns></returns>
        [HttpPost]
        [ProducesResponseType(typeof(TokenDto), 200)]
        [AllowAnonymous]
        public IActionResult Post([FromBody]UserRequestDto dto)
        {
            if (!aliyunSmsService.ValidatePassCode(dto.Phone, dto.PassCode))
            {
                throw new ArgumentException("验证码错误");
            }
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }

            var user = this.userService.Create(dto, ip, RoleType.User);

            return Ok(new TokenDto
            {
                Description = dto.Phone,
                AccessToken = user.GenerateToken(expiration, RoleType.User),
                ExpiresIn = (int)expiration.TotalSeconds,
                EndTime = DateTime.Now.AddSeconds((expiration.TotalSeconds - 12 * 3600))
            });
        }
        #endregion

        #region 登录
        /// <summary>
        /// 登录。
        /// </summary>
        /// <param name="dto">用户登录请求模型</param>
        /// <response code="200">Token</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(TokenDto), 200)]
        [AllowAnonymous]
        public IActionResult Logon([FromBody]UserLogonRequestDto dto)
        {
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }
            var user = this.userService.Logon(dto.Phone, dto.Password, ip);

            if (user == null)
            {
                throw new ArgumentException("用户名或密码不正确。");
            }
            if (!user.Role.HasValue||user.Role.Value != RoleType.User)
            {
                throw new ArgumentException("非用户账号无法登陆");
            }
            return Ok(new TokenDto
            {
                Description = dto.Phone,
                AccessToken = user.GenerateToken(expiration, RoleType.User),
                ExpiresIn = (int)expiration.TotalSeconds,
                EndTime = DateTime.Now.AddSeconds((expiration.TotalSeconds - 12 * 3600))
            });
        }
        #endregion

        #region 微信登录
        /// <summary>
        /// 微信登录。
        /// </summary>
        /// <param name="dto">登录请求模型</param>
        /// <response code="200"></response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(TokenDto), 200)]
        [AllowAnonymous]
        public IActionResult WeChatLogon([FromBody]WechatUserLogonRequestDto dto)
        {
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }
            var weChatUserInfoDto = this.weChatLoginService.GetUserInfo(dto.AccessToken, dto.UnionId);

            var userAuthDto = this.userAuthService.Get(AuthType.WeChat, weChatUserInfoDto.Unionid);
            if (userAuthDto == null)
            {
                throw new ArgumentException("未完成授权绑定账户，无法登录!");
            }
            var user = this.userService.GetUserByUserId(userAuthDto.UserId);

            if (user.AccountStatus == AccountStatus.Stop)
            {
                throw new ArgumentException("此账号已被停止服务。");
            }
            if (user.AccountStatus == AccountStatus.Deleted)
            {
                throw new ArgumentException("此账号不存在。");
            }

            return Ok(new TokenDto
            {
                Description = user.Phone,
                AccessToken = user.GenerateToken(expiration,RoleType.User),
                ExpiresIn = (int)expiration.TotalSeconds,
                EndTime = DateTime.Now.AddSeconds((expiration.TotalSeconds - 12 * 3600))
            });
        }
        #endregion

        #region 绑定微信登录(未登录)
        /// <summary>
        /// 绑定微信登录(未登录)
        /// </summary>
        /// <param name="dto">登录请求模型</param>
        /// <response code="200"></response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(TokenDto), 200)]
        [AllowAnonymous]
        public IActionResult BindingWeChat([FromBody]UserBindWechatRequestDto dto)
        {
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }
            var user = this.userService.Logon(dto.Phone, dto.Password, ip);

            if (user == null)
            {
                user = this.userService.Create(new UserRequestDto() { Phone = dto.Phone, Password = dto.Password, UserName = dto.UserName, PassCode = dto.PassCode }, ip, RoleType.User);
            }
            else
            {
                var userAuthList = this.userAuthService.GetList(user.UserId);
                if (userAuthList.Any(p => p.AuthType == AuthType.WeChat))
                {
                    throw new ArgumentException("此账号已绑定微信账号，无法绑定多个微信账号，请先解绑!");
                }
            }
            UserAuthDto authDto = this.userAuthService.Add(new UserAuthRequestDto()
            {
                UserId = user.UserId,
                AuthType = AuthType.WeChat,
                AuthInfo = dto.AuthInfo,
                UnionId = dto.UnionId
            });
            if (authDto == null)
            {
                throw new ArgumentException("微信授权绑定失败!");
            }
            return Ok(new TokenDto
            {
                Description = dto.Phone,
                AccessToken = user.GenerateToken(expiration, RoleType.User),
                ExpiresIn = (int)expiration.TotalSeconds,
                EndTime = DateTime.Now.AddSeconds((expiration.TotalSeconds - 12 * 3600))
            });
        }
        #endregion

        #region 绑定微信登录(已登录)
        /// <summary>
        /// 绑定微信登录(已登录)
        /// </summary>
        /// <param name="dto">登录请求模型</param>
        /// <response code="200"></response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(NoContentResult), 204)]
        public IActionResult LogonBindingWeChat([FromBody]LogonBindWechatRequestDto dto)
        {
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }

            var userAuthList = this.userAuthService.GetList(this.UserInfo.UserId);
            if (userAuthList.Any(p => p.AuthType == AuthType.WeChat))
            {
                throw new ArgumentException("此账号已绑定微信账号，无法绑定多个微信账号，请先解绑!");
            }

            UserAuthDto authDto = this.userAuthService.Add(new UserAuthRequestDto()
            {
                UserId = this.UserInfo.UserId,
                AuthType = AuthType.WeChat,
                AuthInfo = dto.AuthInfo,
                UnionId = dto.UnionId
            });
            if (authDto == null)
            {
                throw new ArgumentException("微信授权绑定失败!");
            }
            return NoContent();
        }
        #endregion

        #region 获取当前登录用户信息
        /// <summary>
        /// 获取当前登录用户信息
        /// </summary>
        /// <response code="200">当前用户信息</response>
        /// <returns></returns>
        [HttpGet("[action]")]
        [ProducesResponseType(typeof(UserDto), 200)]
        public IActionResult Currently()
        {
            return Ok(this.User);
        }
        #endregion

        #region 刷新Token
        /// <summary>
        /// 刷新Token--用户端需每此检查Token是否已经过期，如果过期了。需要先调用此接口刷新Token
        /// </summary>
        /// <param name="dto">Token</param>
        /// <response code="200"></response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(TokenDto), 200)]
        [AllowAnonymous]
        public IActionResult RefreshToken([FromBody]TokenDto dto)
        {
            DateTime time = DateTime.MinValue;
            DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Local);

            IEnumerable<Claim> claims = TokenExtension.ResolveToken(dto.AccessToken, RoleType.User);
            string exp = claims.Single(p => p.Type.Equals("exp")).Value;
            time = startTime.AddSeconds(int.Parse(exp));

            if (DateTime.UtcNow > time)
            {
                string userIdStr = claims.Single(p => p.Type.Equals(ClaimTypes.Name)).Value.Substring(5);
                string role = claims.Single(p => p.Type.Equals(ClaimTypes.Role)).Value;
                if (!role.Equals(RoleType.User.ToString()))
                {
                    throw new ArgumentException("Token不是有效的");
                }
                if (!long.TryParse(userIdStr, out long userId))
                {
                    throw new ArgumentException("不用不是有效的");
                }
                else
                {
                    var user = userService.GetUserByUserId(userId);
                    if (user == null)
                    {
                        throw new ArgumentException("用户不是有效的");
                    }
                    return Ok(new TokenDto
                    {
                        Description = dto.Description,
                        AccessToken = user.GenerateToken(expiration, RoleType.User),
                        ExpiresIn = (int)expiration.TotalSeconds,
                        EndTime = DateTime.Now.AddSeconds((expiration.TotalSeconds - 12 * 3600))
                    });
                }

            }
            else
            {
                return Ok(dto);
            }
        }
        #endregion

        #region 修改头像
        /// <summary>
        /// 用户修改头像
        /// </summary>
        /// <param name="avatar">头像URL</param>
        /// <response code="200">成功返回true,否则返回false</response>
        /// <returns></returns>
        [HttpPut("[action]")]
        public IActionResult UpdateAvatar([FromQuery(Name = "avatar")]string avatar)
        {
            this.userService.UpdateAvatar(this.UserInfo.Phone, avatar);
            return Ok();
        }
        #endregion

        #region 用户密码找回
        /// <summary>
        /// 用户修改密码
        /// </summary>
        /// <param name="dto">用户注册请求模型</param>
        /// <response code="200">成功返回true,否则返回false</response>
        /// <returns></returns>
        [HttpPut("[action]")]
        [AllowAnonymous]
        public IActionResult Password(UserRequestDto dto)
        {
            if (!aliyunSmsService.ValidatePassCode(dto.Phone, dto.PassCode))
            {
                throw new ArgumentException("验证码错误");
            }
            var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = HttpContext.Connection.RemoteIpAddress.ToString();
            }
            this.userService.UpdatePassword(dto.Phone, dto.Password);
            return Ok();

        }
        #endregion
    }
}
